//
// MemFunCallbackStream.hpp for MemFunCallbackStream in /home/mambou_j//babel-2014
// 
// Made by jacquesquentin mamboumouafo
// Login   <mambou_j@epitech.net>
// 
// Started on  Mon May 14 17:32:19 2012 jacquesquentin mamboumouafo
// Last update Tue May 15 20:22:25 2012 jacquesquentin mamboumouafo
//


#ifndef	__MEMFUNCALLBACKSTREAM_HPP__
#define	__MEMFUNCALLBACKSTREAM_HPP__

#include	"portaudio.h"

#include	"CallbackStream.hpp"
#include	"CallbackInterface.hpp"
#include	"StreamParameters.hpp"
#include	"Exception.hpp"
#include	"InterfaceCallbackStream.hpp"

namespace	portaudio
{
  template<typename T>
  class	MemFunCallbackStream :	public	CallbackStream
  {
  public:
    typedef	int(T::*CallbackFunPtr)(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo *, PaStreamCallbackFlags);

    MemFunCallbackStream()
    {
    }

    MemFunCallbackStream(const StreamParameteres &parameters, T &instance, CallbackFunPtr memFun) : adapter_(instance, memFun)
    {
      open(parameters);
    }

    ~MemFunCallbackStream()
    {
      close();
    }

    void	open(const StreamParameters &parameters, T &instance, CallbackFunPtr memFun)
    {
      adapter_.init(instance, memFun);
      open(parameters);
    }

  private:
    MemFunCallbackStream(const MemFunCallbackStream &)
    MemFunCallbackStream	&operator=(const MemFunCallbackStream &);

    class	MemFunToCallbackInterfaceAdapter :	public	CallbackInterface
    {
    public:
      MemFunToCallbackInterfaceAdapter() {}
      MemFunToCallbackInterfaceAdapter(T &instance, CallbackFunPtr memFun) : instance_(&instance), memFun_(memFun) {}

      void	init(T &instance, CallbackFunPtr memfun)
      {
	instance_ = &instance;
	memFun_ = memFun;
      }

      int	paCallbackFun(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
      {
	return (instance_ -> *memFun_)(inputBuffer, numFrames, timeInfo, statusFlags);
      }

    private:
      T	*instance_;
      CallbackFunPtr	memFun_;
    };

    MemFunToCallbackInterfaceAdapter	adapter_;

    void	open(const StreamParameters &parameters)
    {
      PaError	err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::callbackInterfaceToPaCallbackAdapter, static_cast<void *>(&adapter_));

      if (err != paNoError)
	throw PaException(err);
    }
  };
}

#endif
